package joc.internal.transformer;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

import javassist.CtBehavior;
import javassist.CtClass;
import joc.customize.Contract;
import joc.customize.ForTypeEvaluateAtBeginningOfAllBehaviors;

public class GenericClassTransformer extends ClassTransformer {
	public GenericClassTransformer(Transformer transformer) {
		super(transformer);
	}

	@Override
	public void transform(CtClass clazz) throws Exception {
		for (Class<? extends Annotation> contractAnnotation : Transformer.getContractMap().keySet()) {
			if (clazz.hasAnnotation(contractAnnotation)) {
				Annotation annotation = (Annotation) clazz.getAnnotation(contractAnnotation);
				if (annotation != null) {
					getLogger().info(
							"type " + clazz.getName() + " has contract "
									+ Transformer.getContractMap().get(contractAnnotation).getClass().getName());
					applyContract(clazz, Transformer.getContractMap().get(contractAnnotation), contractAnnotation,
							annotation);
				}
			}
		}
	}

	private void applyContract(CtClass clazz, Class<? extends Contract<?>> contract,
			Class<? extends Annotation> contractAnnotation, Annotation annotation) throws Exception {
		getLogger().info("applying contract " + contract.getClass().getName() + " on class " + clazz.getName());
		for (Method contractMethod : getContractMethodsWithAnnotation(contract,
				ForTypeEvaluateAtBeginningOfAllBehaviors.class)) {
			for (CtBehavior behavior : clazz.getDeclaredBehaviors()) {
				getContractCallString(behavior, contractMethod, contract, contractAnnotation, annotation, true)
						.insertBefore(behavior);
				getLogger().info(
						"inserted " + contract.getClass().getName() + " in beginning of method "
								+ behavior.getLongName());
			}
		}
	}
}
